import redis
import json

# client = redis.Redis(host='xxx.xxx.xx.xx')  # 连接远程的Redis,则需要指定IP
client = redis.Redis()  # 连接远程的Redis,则需要指定IP


def send_sms(phone_number):
    print(f'对{phone_number}发送祝福短信成功！！')
    return True


while True:
    phone_info_bytes = client.lpop('phone_queue')
    # 对一个空的列表执行lpop,会返回None,说明所有的短信都己经发送完毕。
    if not phone_info_bytes:
        print('短信发送完毕！')
        break
    # 列表中的数据是一段JSON格式的字符串,从Redis中读取出来后数据类型为bytes,
    # 由于Python自带的json模块可以处理bytes型的数据,因此不需要将其转为普通字符串。
    phone_info = json.loads(phone_info_bytes.decode())
    # 在初始状态下,phone_info中的数据形如:{’phone_number':12345678},
    # 因此使用字典的get"方法可以防止报错。只有在至少重试一次后,
    # phoneinfo中才会出现retry_times这个Key。
    retry_times = phone_info.get('retry_times', 0)
    phone_number = phone_info['phone_number']
    # 调用send_sms接口发送短信,发送成功则返回True,发送失败则返回False。
    result = send_sms(phone_number)
    if result:
        print(f'手机号：{phone_number} 短信发送成功！')
        continue

    if retry_times >= 3:
        print(f'重试超过3次，放弃手机号：{phone_number}')
        continue
    # 如果发送失败井且重试次数不足3次,那么就把数据重新放进Redis中phone_queue这个列表的右侧。
    # 在放进去之前,retry_times需要加
    next_phone_info = {'phone_number': phone_number, 'retry_times': retry_times + 1}
    client.rpush('phone_queue', json.dumps(next_phone_info))
'''
    10台服务器同时从1台公共的Redis列表左侧读取数据。由于Redis是一个单线程、单进程的数据库,因此10台服务器即使同时对列表执行lpop操作,
Redis也会自动让它们排队,一个一个地弹出最左侧的数据。因此,服务器不会读取到相同的数据,这样就可以实现服务器之间分工协作而不用担心重复
发送短信的问题。
    另外,即使一个手机号发送失败了,把它重新塞入列表,那么不久后另一台服务器就可能又拿到这个手机号并重新发送短信。
    在这个例子中,只需要让服务器获取手机号发送短信就可以了,不需要关心具体哪一台服务器给哪一个手机号发送短信,所以可以使用列表来实现。
所有服务器都从列表里面取于机号,取到以后用相同的发短信逻辑发送短信即可。Redis的列表在这个应用中就是一个队列的角色,数据就在里面,
谁想要谁就来取。
'''
